﻿//----------------------------------------------------------------
// <copyright file="GlobalListBuilderTest.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//----------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MptCodeLibrary;
using MptCodeLibrary.Configuration;
using MptCodeLibrary.Exceptions;
using MptCodeLibrary.TeamFoundation;
using NMock2;

namespace Test.UnitTest
{
    /// <summary>
    /// Unit Tests used to develop GlobalListBuilder via TDD
    /// </summary>
    [TestClass]
    public class GlobalListBuilderTest : UnitTestBase
    {
        private ITeamFoundationFacade teamFoundationFacadeMock;
        private IMptConfiguration mptConfigurationMock;

        private GlobalListBuilder globalListBuilder;
        private GlobalListBuilder_Accessor globalListBuilder_Accessor;

        private const string projectName = "Project1";
        private const string tfsServerName = "http://tfsServer1:8080";

        private const string valueProposition = "Value Proposition";
        private const string deliverable = "Deliverable";

        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        [TestInitialize, DeploymentItem("MptCodeLibrary.dll")]
        public void TestInitialize()
        {
            teamFoundationFacadeMock = Mocks.NewMock<ITeamFoundationFacade>();
            mptConfigurationMock = Mocks.NewMock<IMptConfiguration>();

            globalListBuilder = new GlobalListBuilder(mptConfigurationMock, teamFoundationFacadeMock);

            globalListBuilder_Accessor = new GlobalListBuilder_Accessor(mptConfigurationMock, teamFoundationFacadeMock);
        }
        
        // Use TestCleanup to run code after each test has run
        [TestCleanup]
        public void TestCleanup() { }

        [TestMethod]
        public void VerifyCreationOfGlobalListName()
        {
            const string expectedName = "project1_workitemtype_List";
            string actualName = globalListBuilder_Accessor.GlobalListName("project1", "workitemtype");
            Assert.AreEqual(expectedName, actualName);
        }

        [TestMethod]
        public void VerifyCreationOfGlobalListNameRemovesSpaces()
        {
            const string expectedName = "project 1_workitemtype_List";
            string actualName = globalListBuilder_Accessor.GlobalListName("project 1", "work item type");
            Assert.AreEqual(expectedName, actualName);
        }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void ListItemValueChecksIdParameter()
        {
            globalListBuilder_Accessor.ListItemValue(0, "title");
        }

        [TestMethod, ExpectedException(typeof(ArgumentException))]
        public void ListItemValueChecksTitleParameter()
        {
            globalListBuilder_Accessor.ListItemValue(1, "");
        }

        [TestMethod]
        public void ListItemValueTruncatesReallyLongTitles()
        {
            const string longWorkItemTitle = "Value prop title: This is a really long title the takes up a lot of text.  I don't think anyone would type this much for a title of a bug, but need to verify the code handles it and does not throw a randome exception.  Right here is where the length is exceeded.";
            string expectedTitle = "1: " + longWorkItemTitle.Substring(0, 255 - 3);

            string actualListItem = globalListBuilder_Accessor.ListItemValue(1, longWorkItemTitle);

            Assert.AreEqual(expectedTitle, actualListItem, "The list item didn't shrink");
        }

        [TestMethod, ExpectedException(typeof(MptException))]
        public void DeriveChildWorkItemTypeThrowsWhenUnknownWorkItemType()
        {
            globalListBuilder_Accessor.DeriveChildWorkItemType("unknown work item type");
        }

        [TestMethod]
        public void VerifyDerivingParentChildWorkItemTypes()
        {
            Assert.AreEqual("Feature Group", globalListBuilder_Accessor.DeriveChildWorkItemType("Value Proposition"));
            Assert.AreEqual("Feature", globalListBuilder_Accessor.DeriveChildWorkItemType("Feature Group"));
            Assert.AreEqual("Deliverable", globalListBuilder_Accessor.DeriveChildWorkItemType("Feature"));
            Assert.AreEqual("Task", globalListBuilder_Accessor.DeriveChildWorkItemType("Deliverable"));
        }

        [TestMethod]
        public void DeriveServerNameReturnsServerName()
        {
            const string expectedServerName = "http://Server1:8080";

            XElement workItemChanged = new XElement("WorkItemChangedEvent",
                                                    new XElement("DisplayUrl",
                                                                 string.Format(CultureInfo.InvariantCulture,
                                                                               @"{0}/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163",
                                                                               expectedServerName)));
            List<TeamServerConfiguration> serverNames = new List<TeamServerConfiguration> { new TeamServerConfiguration { ServerName = expectedServerName } };

            Expect.Once.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(serverNames));
            string foundServerName = globalListBuilder_Accessor.DeriveTfsServerName(workItemChanged);

            Assert.IsTrue(expectedServerName.Equals(foundServerName, StringComparison.OrdinalIgnoreCase),
                          "The server should have been found");

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void DeriveServerNameReturnsServerUri()
        {
            const string expectedServerUri = "http://Server1:8080";
            const string expectedServerName = "Server1";

            XElement workItemChanged = new XElement("WorkItemChangedEvent",
                                                    new XElement("DisplayUrl",
                                                                 string.Format(CultureInfo.InvariantCulture,
                                                                               @"{0}/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163",
                                                                               expectedServerUri)));
            List<TeamServerConfiguration> serverNames = new List<TeamServerConfiguration> { new TeamServerConfiguration { ServerName = expectedServerName } };

            Expect.Once.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(serverNames));
            string foundServerName = globalListBuilder_Accessor.DeriveTfsServerName(workItemChanged);

            Assert.IsTrue(expectedServerUri.Equals(foundServerName, StringComparison.OrdinalIgnoreCase),
                          "The server should have been found");

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod, ExpectedException(typeof(MptException))]
        public void DeriveServerNameHandlesNoDisplayUrlElement()
        {
            XElement workItemChanged = new XElement("WorkItemChangedEvent",
                                                    new XElement("Display3Url",
                                                                 string.Format(CultureInfo.InvariantCulture,
                                                                               @"{0}/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163",
                                                                               "http://someserver")));
            
            globalListBuilder_Accessor.DeriveTfsServerName(workItemChanged);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod, ExpectedException(typeof(MptException))]
        public void DeriveServerNameThrowsExceptionIfServerNotInConfigurationServerCollection()
        {
            XElement workItemChanged = new XElement("WorkItemChangedEvent",
                                            new XElement("DisplayUrl", @"http://server1:8080/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163"));
            List<TeamServerConfiguration> serverNames = new List<TeamServerConfiguration>
                                                            {new TeamServerConfiguration {ServerName = "doesnotexist"}};

            Expect.Once.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(serverNames));
            globalListBuilder_Accessor.DeriveTfsServerName(workItemChanged);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void UpdateWorkItemTypeWithGlobalListDoesNotUpdateServerIfAlreadyConfigured()
        {
            string taskWit = string.Format(CultureInfo.InvariantCulture, finalTaskWit,
                                     globalListBuilder_Accessor.GlobalListName(projectName, deliverable));

            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItemTypeForProject")
                .Will(Return.Value(taskWit));
            Expect.Never.On(teamFoundationFacadeMock).Method("UpdateWorkItemTypeForProject");

            globalListBuilder_Accessor.UpdateWorkItemTypeWithGlobalList(tfsServerName, projectName, deliverable);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void RebuildGlobalListsForProjectsReturnsIfNoChangedWorkItems()
        {
            List<TeamServerConfiguration> tfsServers = new List<TeamServerConfiguration> { new TeamServerConfiguration { ServerName = tfsServerName } };
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(tfsServers));

            List<string> teamProjects = new List<string>();
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));

            Stub.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServerName, teamProjects).Will(
                Return.Value(new List<WorkItemSummary>()));

            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void RebuildGlobalListsForProjectsHandlesOneServer()
        {
            List<TeamServerConfiguration> tfsServers = new List<TeamServerConfiguration> { new TeamServerConfiguration { ServerName = tfsServerName } };
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(tfsServers));

            List<string> teamProjects = new List<string>();
            Expect.AtMost(2).On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));

            Stub.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServerName, teamProjects).Will(
                Return.Value(new List<WorkItemSummary> ()));

            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void RebuildGlobalListsForProjectsHandlesTwoServers()
        {
            List<TeamServerConfiguration> tfsServers = new List<TeamServerConfiguration>
                                                           {
                                                               new TeamServerConfiguration {ServerName = tfsServerName},
                                                               new TeamServerConfiguration {ServerName = "ServerName12"}
                                                           };
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(tfsServers));

            List<string> teamProjects = new List<string>();
            Expect.AtMost(2).On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));

            Expect.Once.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServers[0].ServerName, teamProjects).Will(
                Return.Value(new List<WorkItemSummary> ()));
            Expect.Once.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServers[1].ServerName, teamProjects).Will(
                Return.Value(new List<WorkItemSummary> ()));

            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void RebuildGlobalListsForProjectsUsesProjectsInConfig()
        {
            StubTeamServerConfiguration();
            List<string> teamProjects = new List<string> { "project1", "project2" };
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));
            Expect.Once.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServerName, teamProjects).Will(
                Return.Value(new List<WorkItemSummary>()));
            
            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void RebuildGlobalListsForProjectsUsesAllProjectOnTeamServers()
        {
            StubTeamServerConfiguration();
            List<string> teamProjects = new List<string>();
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));
            Expect.Once.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServerName, teamProjects).Will(
                Return.Value(new List<WorkItemSummary>())); 
            
            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void VerifyRebuildGlobalListsWithOneWorkItemTypeChange()
        {
            StubTeamServerConfiguration();
            List<string> teamProjects = new List<string>();
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));

            List<WorkItemSummary> workItemsThatChanged = new List<WorkItemSummary>();
            workItemsThatChanged.Add(new WorkItemSummary(1, "Title1", projectName, valueProposition));
            workItemsThatChanged.Add(new WorkItemSummary(3, "Title3", projectName, valueProposition));

            Expect.Once.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServerName, teamProjects).Will(
                Return.Value(workItemsThatChanged));

            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItemsForProjectOfType").With(tfsServerName, projectName, workItemsThatChanged[0].WorkItemType)
                .Will(Return.Value(workItemsThatChanged));

            XDocument newGL = XDocument.Parse(
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"1: Title1\" /><LISTITEM value=\"3: Title3\" /></GLOBALLIST></GLOBALLISTS>",
                              globalListBuilder_Accessor.GlobalListName(projectName, valueProposition)));

            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList").With(tfsServerName, newGL.ToString());

            ExpectUpdateWorkItemType(valueProposition);

            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        private void ExpectUpdateWorkItemType(string workItemType)
        {
            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItemTypeForProject").Will(Return.Value(initialTaskWit));

            string updateTaskWit = string.Format(CultureInfo.InvariantCulture, finalTaskWit,
                                                 globalListBuilder_Accessor.GlobalListName(projectName, workItemType));

            XDocument updatedWIT = XDocument.Parse(updateTaskWit);
            Expect.Once.On(teamFoundationFacadeMock).Method("UpdateWorkItemTypeForProject").With(
                tfsServerName, projectName, updatedWIT.ToString());
        }

        private void StubUpdateWorkItemType(string workItemType)
        {
            string updateTaskWit = string.Format(CultureInfo.InvariantCulture, finalTaskWit,
                                                 globalListBuilder_Accessor.GlobalListName(projectName, workItemType));

            Stub.On(teamFoundationFacadeMock).Method("GetWorkItemTypeForProject").Will(Return.Value(updateTaskWit));

        }

        [TestMethod]
        public void VerifyRebuildGlobalListsWithTwoWorkItemTypeChanges()
        {
            StubTeamServerConfiguration();
            List<string> teamProjects = new List<string>();
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));

            List<WorkItemSummary> workItemsThatChanged = new List<WorkItemSummary>();
            workItemsThatChanged.Add(new WorkItemSummary(1, "Title1", projectName, valueProposition));
            workItemsThatChanged.Add(new WorkItemSummary(6, "Title6", projectName, deliverable));

            Expect.Once.On(teamFoundationFacadeMock).Method("ChangedWorkItems").With(tfsServerName, teamProjects).Will(
                Return.Value(workItemsThatChanged));

            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItemsForProjectOfType").With(tfsServerName,
                                                                                                 projectName,
                                                                                                 valueProposition)
                .Will(Return.Value(new List<WorkItemSummary> { workItemsThatChanged[0] }));

            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItemsForProjectOfType").With(tfsServerName,
                                                                                                 projectName,
                                                                                                 deliverable)
                .Will(Return.Value(new List<WorkItemSummary> { workItemsThatChanged[1] }));

            XDocument newGL = XDocument.Parse(
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"1: Title1\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListBuilder_Accessor.GlobalListName(projectName, valueProposition)));
            
            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList").With(tfsServerName, newGL.ToString());
            ExpectUpdateWorkItemType(valueProposition);
            
            newGL = XDocument.Parse(string.Format(CultureInfo.InvariantCulture,
                                                  "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"6: Title6\"/></GLOBALLIST></GLOBALLISTS>",
                                                  globalListBuilder_Accessor.GlobalListName(projectName,
                                                                                   deliverable)));

            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList").With(tfsServerName, newGL.ToString());

            ExpectUpdateWorkItemType(deliverable);

            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }
        
        [TestMethod]
        public void RebuildGlobalListUpdatesTheChildWorkItemTypeIfNewlyAddedGlobalList()
        {
            StubTeamServerConfiguration();
            List<string> teamProjects = new List<string>();
            Expect.Once.On(mptConfigurationMock).GetProperty("TeamProjects").Will(Return.Value(teamProjects));

            List<WorkItemSummary> workItemsThatChanged = new List<WorkItemSummary>();
            workItemsThatChanged.Add(new WorkItemSummary(1, "Title1", projectName, deliverable));
            workItemsThatChanged.Add(new WorkItemSummary(3, "Title3", projectName, deliverable));

            Stub.On(teamFoundationFacadeMock).Method("ChangedWorkItems").Will(Return.Value(workItemsThatChanged));

            Stub.On(teamFoundationFacadeMock).Method("GetWorkItemsForProjectOfType").Will(Return.Value(workItemsThatChanged));

            Stub.On(teamFoundationFacadeMock).Method("SetGlobalList");
            
            ExpectUpdateWorkItemType(deliverable);

            globalListBuilder.RebuildGlobalListsForProjects();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void UpdateGlobalListAddsNewGlobalListForWorkItemTypeIfNotFound()
        {
            const string workItemType = valueProposition;
            const string newWorkItemTitle = "Value prop title";
            const int newWorkItemId = 75;

            string globalListName = globalListBuilder_Accessor.GlobalListName(projectName, workItemType);
            const string existingGL = "<GLOBALLISTS></GLOBALLISTS>";

            XDocument newGL = XDocument.Parse(
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"{1}: {2}\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListName, newWorkItemId, newWorkItemTitle));

            string eventXml = string.Format(CultureInfo.InvariantCulture, NewWorkItemXml, projectName,
                newWorkItemTitle, workItemType, tfsServerName, newWorkItemId);

            StubTeamServerConfiguration();

            Expect.Once.On(teamFoundationFacadeMock).Method("GetGlobalLists").With(tfsServerName.ToLowerInvariant()).
                Will(Return.Value(existingGL));

            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList")
                .With(tfsServerName.ToLowerInvariant(), newGL.ToString());

            Stub.On(teamFoundationFacadeMock).Method("GetWorkItemTypeForProject").Will(Return.Value(initialTaskWit));
            Stub.On(teamFoundationFacadeMock).Method("UpdateWorkItemTypeForProject");

            globalListBuilder.UpdateGlobalList(eventXml);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void UpdateGlobalListUpdatesWitForChildWhenGlobalListForWorkItemTypeNotFound()
        {
            const string parentWorkItemType = valueProposition;
            const string childWorkItemType = "Feature Group";
            const string newWorkItemTitle = "Value prop title";
            const int newWorkItemId = 75;

            const string existingGL = "<GLOBALLISTS></GLOBALLISTS>";

            string eventXml = string.Format(CultureInfo.InvariantCulture, NewWorkItemXml, projectName,
                newWorkItemTitle, parentWorkItemType, tfsServerName, newWorkItemId);

            StubTeamServerConfiguration();

            Stub.On(teamFoundationFacadeMock).Method("GetGlobalLists").Will(Return.Value(existingGL));

            Stub.On(teamFoundationFacadeMock).Method("SetGlobalList");

            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItemTypeForProject").With(
                tfsServerName.ToLowerInvariant(), projectName, childWorkItemType).Will(Return.Value(initialTaskWit));

            string updateTaskWit = string.Format(CultureInfo.InvariantCulture, finalTaskWit,
                                                 globalListBuilder_Accessor.GlobalListName(projectName, parentWorkItemType));

            // Go from string -> XDocument -> string so that the formatting is the same.  If the formatting is off
            // then the string won't be equal and the test fails.
            XDocument updatedWIT = XDocument.Parse(updateTaskWit);
            Expect.Once.On(teamFoundationFacadeMock).Method("UpdateWorkItemTypeForProject").With(
                tfsServerName.ToLowerInvariant(), projectName, updatedWIT.ToString());

            globalListBuilder.UpdateGlobalList(eventXml);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void NewValuePropositionIsAddedToCorrectGlobalList()
        {
            const string newWorkItemTitle = "Value prop title";
            const int newWorkItemId = 75;

            string globalListName = globalListBuilder_Accessor.GlobalListName(projectName, valueProposition);
            string existingGL =
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"74: Title1\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListName);
            XDocument newGL = XDocument.Parse(
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"74: Title1\"/><LISTITEM value=\"{1}: {2}\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListName, newWorkItemId, newWorkItemTitle));
             
            string eventXml = string.Format(CultureInfo.InvariantCulture, NewWorkItemXml, projectName,
                newWorkItemTitle, valueProposition, tfsServerName, newWorkItemId);

            StubTeamServerConfiguration();

            Expect.Once.On(teamFoundationFacadeMock).Method("GetGlobalLists").With(tfsServerName.ToLowerInvariant()).
                Will(Return.Value(existingGL));

            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList")
                .With(tfsServerName.ToLowerInvariant(), newGL.ToString());

            StubUpdateWorkItemType(valueProposition);

            globalListBuilder.UpdateGlobalList(eventXml);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void ChangeEventForExistingWorkItemButNotTitleDoesNotCauseAnUpdate()
        {
            const string workItemType = valueProposition;
            const string workItemTitle = "Value prop title";
            const int workItemId = 75;

            string eventXml = string.Format(CultureInfo.InvariantCulture, ChangedWorkItemXml, projectName, workItemTitle,
                                            workItemType, tfsServerName, workItemId);

            Expect.Never.On(mptConfigurationMock).GetProperty("TeamServers");
            Expect.Never.On(teamFoundationFacadeMock).Method("GetGlobalLists");
            Expect.Never.On(teamFoundationFacadeMock).Method("SetGlobalList");

            globalListBuilder.UpdateGlobalList(eventXml);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void UpdateGlobalListHandlesMultipleSubscriptionsForNewWorkItem()
        {
            const string workItemTitle = "Value prop title";
            const int workItemId = 75;

            string eventXml = string.Format(CultureInfo.InvariantCulture, NewWorkItemXml, projectName, workItemTitle,
                                            valueProposition, tfsServerName, workItemId);
            
            string existingGL =
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"{1}: {2}\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListBuilder_Accessor.GlobalListName(projectName, valueProposition), workItemId, workItemTitle);
           
            StubTeamServerConfiguration();

            Expect.Once.On(teamFoundationFacadeMock).Method("GetGlobalLists").With(tfsServerName.ToLowerInvariant()).
                Will(Return.Value(existingGL));
            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList").With(tfsServerName.ToLowerInvariant(),
                                                                                  XDocument.Parse(existingGL).ToString());

            StubUpdateWorkItemType(valueProposition);

            globalListBuilder.UpdateGlobalList(eventXml);
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [TestMethod]
        public void ChangeEventForExistingWorkItemWhereTheTitleChangesUpdatesGlobalList()
        {
            const string existingWorkItemTitle = "Value prop title";
            const string newWorkItemTitle = "Updated prop title";
            const int workItemId = 75;

            string eventXml = string.Format(CultureInfo.InvariantCulture, ChangedWorkItemTitleXml, projectName, existingWorkItemTitle,
                                valueProposition, tfsServerName, workItemId, newWorkItemTitle);

            string globalListName = globalListBuilder_Accessor.GlobalListName(projectName, valueProposition);
            string existingGL =
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"74: Title1\"/><LISTITEM value=\"{1}: {2}\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListName, workItemId, existingWorkItemTitle);
            XDocument newGL = XDocument.Parse(
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"74: Title1\"/><LISTITEM value=\"{1}: {2}\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListName, workItemId, newWorkItemTitle));

            StubTeamServerConfiguration();
            
            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItem").With(tfsServerName.ToLowerInvariant(), workItemId).Will(
                Return.Value(new WorkItemSummary(workItemId, existingWorkItemTitle, projectName, valueProposition)));

            Expect.Once.On(teamFoundationFacadeMock).Method("GetGlobalLists").With(tfsServerName.ToLowerInvariant()).
                Will(Return.Value(existingGL));

            Expect.Once.On(teamFoundationFacadeMock).Method("SetGlobalList")
                .With(tfsServerName.ToLowerInvariant(), newGL.ToString());

            Stub.On(teamFoundationFacadeMock).Method("UpdateExistingWorkItemsWithNewParent");
            StubUpdateWorkItemType(valueProposition);

            globalListBuilder.UpdateGlobalList(eventXml);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }
        
        [TestMethod]
        public void ChangeEventForExistingWorkItemWhereTheTitleChangesUpdatesExistingWorkItems()
        {
            const string existingWorkItemTitle = "Value prop title";
            const string newWorkItemTitle = "Updated prop title";
            const int workItemId = 75;

            string existingParentShortName = string.Format(CultureInfo.InvariantCulture, "{0}: {1}", workItemId,
                                                           existingWorkItemTitle);
            string newParentShortName = string.Format(CultureInfo.InvariantCulture, "{0}: {1}", workItemId,
                                                      newWorkItemTitle);

            string eventXml = string.Format(CultureInfo.InvariantCulture, ChangedWorkItemTitleXml, projectName, existingWorkItemTitle,
                                valueProposition, tfsServerName, workItemId, newWorkItemTitle);

            string globalListName = globalListBuilder_Accessor.GlobalListName(projectName, valueProposition);
            string existingGL =
                string.Format(CultureInfo.InvariantCulture,
                              "<GLOBALLISTS><GLOBALLIST name=\"{0}\"><LISTITEM value=\"74: Title1\"/><LISTITEM value=\"{1}: {2}\"/></GLOBALLIST></GLOBALLISTS>",
                              globalListName, workItemId, existingWorkItemTitle);

            StubTeamServerConfiguration();

            Expect.Once.On(teamFoundationFacadeMock).Method("GetWorkItem").With(tfsServerName.ToLowerInvariant(), workItemId).Will(
                Return.Value(new WorkItemSummary(workItemId, existingWorkItemTitle, projectName, valueProposition)));

            Stub.On(teamFoundationFacadeMock).Method("GetGlobalLists").Will(Return.Value(existingGL));

            Stub.On(teamFoundationFacadeMock).Method("SetGlobalList");

            Expect.Once.On(teamFoundationFacadeMock).Method("UpdateExistingWorkItemsWithNewParent").With(tfsServerName.ToLowerInvariant(),
                                                                                                         projectName,
                                                                                                         existingParentShortName,
                                                                                                         newParentShortName);

            StubUpdateWorkItemType(valueProposition);

            globalListBuilder.UpdateGlobalList(eventXml);

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        private void StubTeamServerConfiguration()
        {
            TeamServerConfiguration config = new TeamServerConfiguration {ServerName = tfsServerName};

            List<TeamServerConfiguration> serverNames = new List<TeamServerConfiguration> { config };
            Stub.On(mptConfigurationMock).GetProperty("TeamServers").Will(Return.Value(serverNames));
        }

        #region tfsEventXmls
        private const string NewWorkItemXml = @"
<WorkItemChangedEvent xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema\'>
  <PortfolioProject>{0}</PortfolioProject> 
  <ProjectNodeId>60ed3e5c-2e38-4494-a7a7-2e503a6f4d90</ProjectNodeId> 
  <AreaPath>\{0}</AreaPath> 
  <Title>{0} Work Item Created: {2} 11163 - {1}</Title> 
  <WorkItemTitle>{1}</WorkItemTitle> 
  <Subscriber>NORTHAMERICA\mattwest</Subscriber> 
  <ChangerSid>S-1-5-21-124525095-708259637-1543119021-523981</ChangerSid> 
  <DisplayUrl>{3}/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163</DisplayUrl> 
  <TimeZone>Pacific Daylight Time</TimeZone> 
  <TimeZoneOffset>-07:00:00</TimeZoneOffset> 
  <ChangeType>New</ChangeType> 
    <CoreFields>
        <IntegerFields>
            <Field>
                <Name>ID</Name> 
                <ReferenceName>System.Id</ReferenceName> 
                <OldValue>0</OldValue> 
                <NewValue>{4}</NewValue> 
            </Field>
        </IntegerFields>
        <StringFields>
            <Field>
                <Name>Work Item Type</Name> 
                <ReferenceName>System.WorkItemType</ReferenceName> 
                <OldValue /> 
                <NewValue>{2}</NewValue> 
            </Field>
            <Field>
                <Name>Title</Name> 
                <ReferenceName>System.Title</ReferenceName> 
                <OldValue /> 
                <NewValue>{1}</NewValue> 
            </Field>
        </StringFields>
    </CoreFields>
    <ChangedFields>
        <StringFields>
            <Field>
                <Name>Title</Name>
                <ReferenceName>System.Title</ReferenceName>
                <OldValue />
                <NewValue>{1}</NewValue>
            </Field>
            <Field>
                <Name>WIT Category</Name>
                <ReferenceName>Microsoft.VSTS.Common.WITCategory</ReferenceName>
                <OldValue /> 
                <NewValue>{2}</NewValue> 
            </Field>
            
        </StringFields>
    </ChangedFields>
</WorkItemChangedEvent>
";
        private const string ChangedWorkItemXml = @"
<WorkItemChangedEvent xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema\'>
  <PortfolioProject>{0}</PortfolioProject> 
  <ProjectNodeId>60ed3e5c-2e38-4494-a7a7-2e503a6f4d90</ProjectNodeId> 
  <AreaPath>\{0}</AreaPath> 
  <Title>{0} Work Item Created: {2} 11163 - {1}</Title> 
  <WorkItemTitle>{1}</WorkItemTitle> 
  <Subscriber>NORTHAMERICA\mattwest</Subscriber> 
  <ChangerSid>S-1-5-21-124525095-708259637-1543119021-523981</ChangerSid> 
  <DisplayUrl>{3}/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163</DisplayUrl> 
  <TimeZone>Pacific Daylight Time</TimeZone> 
  <TimeZoneOffset>-07:00:00</TimeZoneOffset> 
  <ChangeType>Change</ChangeType> 
    <CoreFields>
        <IntegerFields>
            <Field>
                <Name>ID</Name> 
                <ReferenceName>System.Id</ReferenceName> 
                <OldValue>{4}</OldValue> 
                <NewValue>{4}</NewValue> 
            </Field>
        </IntegerFields>
        <StringFields>
            <Field>
                <Name>Work Item Type</Name> 
                <ReferenceName>System.WorkItemType</ReferenceName> 
                <OldValue>{2}</OldValue> 
                <NewValue>{2}</NewValue> 
            </Field>
            <Field>
                <Name>Title</Name> 
                <ReferenceName>System.Title</ReferenceName> 
                <OldValue>{1}</OldValue> 
                <NewValue>{1}</NewValue> 
            </Field>
        </StringFields>
    </CoreFields>
    <ChangedFields>
        <StringFields>
        </StringFields>
    </ChangedFields>
</WorkItemChangedEvent>";

        private const string ChangedWorkItemTitleXml = @"
<WorkItemChangedEvent xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema\'>
  <PortfolioProject>{0}</PortfolioProject> 
  <ProjectNodeId>60ed3e5c-2e38-4494-a7a7-2e503a6f4d90</ProjectNodeId> 
  <AreaPath>\{0}</AreaPath> 
  <Title>{0} Work Item Created: {2} 11163 - {1}</Title> 
  <WorkItemTitle>{5}</WorkItemTitle> 
  <Subscriber>NORTHAMERICA\mattwest</Subscriber> 
  <ChangerSid>S-1-5-21-124525095-708259637-1543119021-523981</ChangerSid> 
  <DisplayUrl>{3}/WorkItemTracking/WorkItem.aspx?artifactMoniker=11163</DisplayUrl> 
  <TimeZone>Pacific Daylight Time</TimeZone> 
  <TimeZoneOffset>-07:00:00</TimeZoneOffset> 
  <ChangeType>Change</ChangeType> 
    <CoreFields>
        <IntegerFields>
            <Field>
                <Name>ID</Name> 
                <ReferenceName>System.Id</ReferenceName> 
                <OldValue>{4}</OldValue> 
                <NewValue>{4}</NewValue> 
            </Field>
        </IntegerFields>
        <StringFields>
            <Field>
                <Name>Work Item Type</Name> 
                <ReferenceName>System.WorkItemType</ReferenceName> 
                <OldValue>{2}</OldValue> 
                <NewValue>{2}</NewValue> 
            </Field>
            <Field>
                <Name>Title</Name> 
                <ReferenceName>System.Title</ReferenceName> 
                <OldValue>{1}</OldValue> 
                <NewValue>{5}</NewValue> 
            </Field>
        </StringFields>
    </CoreFields>
    <ChangedFields>
        <StringFields>
            <Field>
                <Name>Title</Name> 
                <ReferenceName>System.Title</ReferenceName> 
                <OldValue>{1}</OldValue> 
                <NewValue>{5}</NewValue> 
            </Field>
        </StringFields>
    </ChangedFields>
</WorkItemChangedEvent>";

        #endregion

        #region tfsWitXmls
        private const string initialTaskWit = @"
<WITD application=""Work item type editor"" version=""1.0"">
    <WORKITEMTYPE name=""Task"">
        <DESCRIPTION>Includes information to track a task</DESCRIPTION>
        <FIELDS>
            <FIELD name=""Title"" refname=""System.Title"" type=""String"">
                <HELPTEXT>Short description of the task used to differentiate it in a list or report</HELPTEXT>
                <REQUIRED/>
            </FIELD>
                
            <FIELD name=""Parent Short Name"" refname=""Microsoft.VSTS.Common.ParentShortName"" type=""String"" reportable=""dimension"">
                <HELPTEXT>Short name of the parent work item</HELPTEXT>
                <!-- TODO:  This rule must be manually edited and turned on after a new team project is created. -->
                <ALLOWEDVALUES expanditems=""true"">
                    <LISTITEM value=""0: Not Applicable"" />
                    <!--<GLOBALLIST name=""ProjectName_Deliverable_List""/>-->
                </ALLOWEDVALUES>
            </FIELD>
            <FIELD name=""Assigned To"" refname=""System.AssignedTo"" type=""String"">
                <HELPTEXT>The person assigned to do the work</HELPTEXT>
                <ALLOWEDVALUES expanditems=""true"" filteritems=""excludegroups"">
                    <LISTITEM value=""[Project]\Coordinators"" />
                    <LISTITEM value=""[Project]\Developers"" />
                </ALLOWEDVALUES>
            </FIELD>
        </FIELDS>
    </WORKITEMTYPE>
</WITD>
";
        private const string finalTaskWit = @"
<WITD application=""Work item type editor"" version=""1.0"">
    <WORKITEMTYPE name=""Task"">
        <DESCRIPTION>Includes information to track a task</DESCRIPTION>
        <FIELDS>
            <FIELD name=""Title"" refname=""System.Title"" type=""String"">
                <HELPTEXT>Short description of the task used to differentiate it in a list or report</HELPTEXT>
                <REQUIRED/>
            </FIELD>
                
            <FIELD name=""Parent Short Name"" refname=""Microsoft.VSTS.Common.ParentShortName"" type=""String"" reportable=""dimension"">
                <HELPTEXT>Short name of the parent work item</HELPTEXT>
                <!-- TODO:  This rule must be manually edited and turned on after a new team project is created. -->
                <ALLOWEDVALUES expanditems=""true"">
                    <GLOBALLIST name=""{0}""/>
                </ALLOWEDVALUES>
            </FIELD>
            <FIELD name=""Assigned To"" refname=""System.AssignedTo"" type=""String"">
                <HELPTEXT>The person assigned to do the work</HELPTEXT>
                <ALLOWEDVALUES expanditems=""true"" filteritems=""excludegroups"">
                    <LISTITEM value=""[Project]\Coordinators"" />
                    <LISTITEM value=""[Project]\Developers"" />
                </ALLOWEDVALUES>
            </FIELD>
        </FIELDS>
    </WORKITEMTYPE>
</WITD>
";

        #endregion

    }
}
